﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace GMS.Client.Core
{
    /// <summary>
    /// Windows接口类
    /// </summary>
    public class Win32API
    {
        [DllImport("user32")]
        [return: MarshalAs(UnmanagedType.Bool)]
        //IMPORTANT : LPARAM  must be a pointer (InterPtr) in VS2005, otherwise an exception will be thrown
        private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
        //the callback function for the EnumChildWindows
        private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

        //if found  return the handle , otherwise return IntPtr.Zero
        [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
        public static extern int SendMessage_SetValue(IntPtr hWnd, int Msg, int wParam, string lParam);

        [DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
        public static extern int SendMessage_GetValue(IntPtr hWnd, int Msg, int wParam, StringBuilder lParam);

        [DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        public static extern IntPtr GetParent(IntPtr hWnd);

        [DllImport("user32.dll", EntryPoint = "SetForegroundWindow", SetLastError = true)]
        public static extern void SetForegroundWindow(IntPtr hwnd);

        [DllImport("user32.dll", EntryPoint = "MoveWindow")]
        public static extern int MoveWindow(IntPtr hwnd, int x, int y, int nWidth, int nHeight, bool bRepaint);

        [DllImport("user32.dll")]
        private static extern int GetWindowRect(IntPtr hwnd, out  Rect lpRect);

        private struct Rect
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        private static string m_classname; // class name to look for
        private static string m_caption; // caption name to look for

        private static DateTime start;
        private static int m_timeout;//If exceed the time. Indicate no windows found.

        private static IntPtr m_hWnd; // HWND if found
        public static IntPtr FoundHandle
        {
            get { return m_hWnd; }
        }

        private static bool m_IsTimeOut;
        public static bool IsTimeOut
        {
            get{return m_IsTimeOut;}
            set { m_IsTimeOut = value; }
        }

        /// <summary>
        /// 根据类名获取所有子句柄
        /// </summary>
        /// <param name="parentHandle"></param>
        /// <param name="className"></param>
        /// <returns></returns>
        public static List<IntPtr> GetChildHandlesByParentHandle(IntPtr parentHandle)
        {
            var handles = new List<IntPtr>();
            var tmpHandle = FindWindowEx(parentHandle, IntPtr.Zero, null, null);
            while (tmpHandle != IntPtr.Zero)
            {
                tmpHandle = FindWindowEx(parentHandle, tmpHandle, null, null);
                if (tmpHandle != IntPtr.Zero)
                {
                    handles.Add(tmpHandle);
                }
            }
            return handles;
        }

        /// <summary>
        /// 获取子窗口句柄
        /// </summary>
        /// <param name="parentHandle"></param>
        /// <param name="className"></param>
        /// <param name="titleName"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public static IntPtr GetChildWindowHandle(IntPtr parentHandle, string className, string titleName, int timeout)
        {
            m_hWnd = IntPtr.Zero;
            m_classname = className;
            m_caption = titleName;
            m_timeout = timeout;
            start = DateTime.Now;
            return FindChildClassHwnd(parentHandle, IntPtr.Zero) ? FoundHandle : IntPtr.Zero;
        }

        public static void MoveWindow(IntPtr handle, int x, int y)
        {
            var rect = new Rect();
            GetWindowRect(handle, out rect);
            MoveWindow(handle, x, y, (rect.Right - rect.Left), (rect.Bottom - rect.Top), true);
        }

        private static bool FindChildClassHwnd(IntPtr hwndParent, IntPtr lParam)
        {
            EnumWindowProc childProc = new EnumWindowProc(FindChildClassHwnd);
            IntPtr hwnd = FindWindowEx(hwndParent, IntPtr.Zero, m_classname, m_caption);
            if (hwnd != IntPtr.Zero)
            {
                m_hWnd = hwnd; // found: save it
                m_IsTimeOut = false;
                return false; // stop enumerating
            }

            DateTime end = DateTime.Now;

            if (start.AddSeconds(m_timeout) < end)
            {
                m_IsTimeOut = true;
                return false;
            }

            EnumChildWindows(hwndParent, childProc, IntPtr.Zero); // recurse  redo FindChildClassHwnd
            return true;// keep looking
        }

    }
}
